#include <iostream>
#include <fstream>
#include "B_Form.h"
#include "PP_Form.h"
#include <cmath>
#include <algorithm>
#include <vector>
#include <jsoncpp/json/json.h>
using namespace std;

class Fun : public Function
{
public:
    double operator()(double _x)
    {
        double y;
        y = 1.0/(1.0 + 25.0*_x*_x);
        return y;
    }
    double diff(double _x) 
    {
        double y;
        y = -50.0*_x/pow(1 + 25.0*_x*_x, 2);
        return y;  
    }
    double diff2(double _x)
    {
        double y;
        y = 50.0*(75.0*_x*_x - 1)/pow(1.0 + 25.0*_x*_x, 3);
        return y;  
    }
};

int main()
{
    Json::Reader reader;
    Json::Value root;
 
    /**
     * get the date
    */
    ifstream in("./date/input/A.json", ios::binary);
    if (!in.is_open())
    {
	    cout << "error: cannot open file." << endl;
	    return -1;
    }
	
    vector<int> point_Num;
    double left, right;
    int choice, k;
    Fun f;

    if (reader.parse(in, root))
	{

        choice = root["choice"].asInt();
        k = root["k"].asInt();
        left = root["interval_left"].asDouble();
        right = root["interval_right"].asDouble();

        if (left > right)
        {
            cerr<< "error: Invalid interval input." <<endl;
		    return -1;
        }

        for (int i = 0; i < root["n"].size(); i++)
	    {
	        int temp_n = root["n"][i].asInt();
	        point_Num.push_back(temp_n);
	    }
    }

    /**
     * B-Form
    */
    ofstream foutB_Form, foutB_Form1;

    foutB_Form.open("probA_B-Form_points.txt");
    foutB_Form1.open("probA_B-Form_error.txt");
    foutB_Form << "order = " << k << ", choice = " << choice << endl;
    foutB_Form1 << "order = " << k << ", method = " << choice << endl;

    for (int i = 0; i < point_Num.size(); i++)
	{
        vector<double> T;
        for (int j = 0; j < point_Num[i]; j++)
		{
            T.push_back(left + j*(right-left)/(point_Num[i]-1));
		}

        Bspline P(f, T,choice, k);
        P.cal();
        foutB_Form << "N = " << point_Num[i] << endl;
        for (int j = 0; j < 200; j++)
		{
            foutB_Form << P(left + j*0.01) << ", ";
		}
        foutB_Form << P(right) <<endl<<endl;;

        foutB_Form1 << "N = " << point_Num[i] <<endl;
        double error = 0;
        for (int j = 0; j < point_Num[i] - 1; j++)
		{
            if (fabs(P(0.5*(T[j] + T[j+1])) - f(0.5*(T[j] + T[j+1]))) > error)
                error = fabs(P(0.5*(T[j] + T[j+1])) - f(0.5*(T[j] + T[j+1])));
		}
        foutB_Form1 << error << endl<<endl;

	}
    foutB_Form.close();
    foutB_Form1.close();


    /**
     * pp-Form
    */
    ofstream foutPP_Form, foutPP_Form1;

    foutPP_Form.open("probA_PP-Form_points.txt");
    foutPP_Form1.open("probA_PP-Form_error.txt");
    foutPP_Form << "order = " << k << ", choice = " << choice << endl;
    foutPP_Form1 << "max interpolation error with order = " << k << ", method = " << choice << endl;

    for (int i = 0; i < point_Num.size(); i++)
	{
        vector<double> T;
        for (int j = 0; j < point_Num[i]; j++)
		{
            T.push_back(left + j*(right-left)/(point_Num[i]-1));
		}

        PP_Form P(f, T,choice, k);
        P.cal();
        foutPP_Form << "N = " << point_Num[i] << ", sampling with interval 0.01 in [-1,1]" << endl;
        for (int j = 0; j < 200; j++)
		{
            foutPP_Form << P(left + j*0.01) << ", ";
		}
        foutPP_Form << P(right) <<endl<<endl;

        foutPP_Form1 << "N = " << point_Num[i] <<endl;
        double error = 0;
        for (int j = 0; j < point_Num[i] - 1; j++)
		{
            if (fabs(P(0.5*(T[j] + T[j+1])) - f(0.5*(T[j] + T[j+1]))) > error)
                error = fabs(P(0.5*(T[j] + T[j+1])) - f(0.5*(T[j] + T[j+1])));
		}
        foutPP_Form1 << error << endl<<endl;

	}
    foutPP_Form.close();
    foutPP_Form1.close();
    return 0;
}



